package com.xxgc.demo.controller;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.DesensitizedUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.digest.DigestAlgorithm;
import cn.hutool.crypto.digest.Digester;
import cn.hutool.jwt.JWT;
import cn.hutool.jwt.JWTUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.plugins.pagination.PageDTO;
import com.xxgc.demo.controller.annotations.CheckIdCardDate;
import com.xxgc.demo.controller.dto.UserInfoDTO;
import com.xxgc.demo.controller.dto.UserInfoLoginDTO;
import com.xxgc.demo.controller.error.myerror.UserPhoneAlreadyExistsException;
import com.xxgc.demo.controller.result.Result;
import com.xxgc.demo.controller.vo.NameAuthenticationVO;
import com.xxgc.demo.controller.vo.UserInfoLoginVO;
import com.xxgc.demo.controller.vo.UserInfoRegisterVO;
import com.xxgc.demo.entity.Users;
import com.xxgc.demo.service.IUsersService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.Parameters;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import java.io.UnsupportedEncodingException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @Author:SJY
 * @Date :2023/9/5 - 09 - 05 - 16:02
 * thanksjava@qq.com
 * @ResponseBody + @Controller = @RestController
 */
@CacheConfig(cacheNames = "user")
@Slf4j
@Tag(name = "用户登陆")
@RestController
@RequestMapping("/demo2")
public class Demo2Controller {
    //导业务逻辑层
    @Autowired
    private IUsersService iUsersService;

    //token加解密用的秘钥
    private static final String secretKey = "Sjy13213#45sfdsAAsdsa%@#";

    @Operation(summary = "获取信息测试",description = "测试用")
    @GetMapping("/msg")
    public String getMsg(){
        return "Hello Spring MVC";
    }


    @Parameters({
            @Parameter(name = "uname",description = "用户名",required = true,example = "admin"),
            @Parameter(name = "pword",description = "密码",required = true,example = "123"),
    })
    @Operation(summary = "用户名密码登陆",description = "使用用户名密码登陆")
    @PostMapping("/login")
    public String login(String uname, String pword, HttpServletResponse response){
        if("admin".equals(uname) && "123".equals(pword)){
            // 假如查询了service 并返回了用户对象 且用户id是 135
            Map<String, Object> map = new HashMap<String, Object>() {
                private static final long serialVersionUID = 1L;
                {
                    put("uid", 135);//用户id
                    put("expire_time", System.currentTimeMillis() + 1000 * 60 * 60 * 24 * 15);//有效时间15天
                }
            };
            String token = JWTUtil.createToken(map, secretKey.getBytes());
            response.setHeader("token",token);
            return "登陆成功";
        }else{
            return "登陆失败";
        }
    }

    @Operation(summary = "用户名手机号密码登陆",description = "使用用户手机号密码登陆")
    @PostMapping("/login/phone")
    public Result<UserInfoLoginDTO> loginByPhone(@RequestBody UserInfoLoginVO userInfoLoginVO){
        //假装在操作业务逻辑层
        return null;
    }

    /**
     * cacheNames/value 缓存组件的名字
     * condition 满足条件才缓存
     * unless 满足条件不缓存
     *
     * 1703589844340633602
     * 1703585025844506626
     */
    @Cacheable(key = "#userId",condition="#userId == 1703589844340633602L")
    @Parameters({
            @Parameter(name = "userId",description = "用户id",required = true,example = "1"),
    })
    @Operation(summary = "查询用户个人信息",description = "通过id查询用户个人信息")
    @PostMapping("/login/userInfoById/{userId}")
    public Result<UserInfoDTO> getUserInfoById(@PathVariable Long userId){
        //通过id查询用户
        Users user = iUsersService.getById(userId);
        UserInfoDTO userInfoDTO = new UserInfoDTO();
        //Entity转DTO
        BeanUtil.copyProperties(user,userInfoDTO);

        //身份证数据脱敏
        userInfoDTO.setIdCard(
                DesensitizedUtil.idCardNum(userInfoDTO.getIdCard(), 6, 4)
        );
        //电话号码脱敏
        userInfoDTO.setPhone(
                DesensitizedUtil.mobilePhone(userInfoDTO.getPhone())
        );
        //姓名脱敏
        userInfoDTO.setNickName(
                DesensitizedUtil.chineseName(userInfoDTO.getNickName())
        );
        return Result.ok(userInfoDTO);
    }


    //写一个注册  要求填用户名、手机号、密码 只用返回成功或失败
    @Operation(summary = "用户注册",description = "用户注册")
    @PostMapping("/login/registerUser")
    public Result registerUser(@RequestBody @Valid UserInfoRegisterVO userInfoRegisterVO) throws UnsupportedEncodingException {
        //查重
        //查询条件
        QueryWrapper<Users> qw = new QueryWrapper<>();
        qw.eq("phone",userInfoRegisterVO.getPhone());
        Users one = iUsersService.getOne(qw);
        if(ObjectUtil.isNotNull(one)){
            throw new UserPhoneAlreadyExistsException();
            //return Result.error().code(400).msg("请求失败").data(new String[]{"手机号已被注册"});
        }

        //密码加密  MD5
        Digester md5 = new Digester(DigestAlgorithm.MD5);
        //获取随机盐值
        String simpleUUID = IdUtil.simpleUUID();
        byte[] salt = simpleUUID.getBytes("UTF8");
        //加盐操作
        md5.setSalt(salt);
        // 加密之后的
        String digestHex = md5.digestHex(userInfoRegisterVO.getPassWord());
        //加密之后密码放回去
        userInfoRegisterVO.setPassWord(digestHex);

        Users users = new Users();
        //VO的字段转给Entity？
        BeanUtil.copyProperties(userInfoRegisterVO, users);

        //把盐放进去
        //users.setSalt(simpleUUID);

        System.out.println("users.toString() = " + users.toString());
        //业务逻辑层
        iUsersService.save(users);
        return Result.ok().msg("注册成功");
    }


    // 实名认证接口 ，要求补充用户信息有（身份证号码、姓名、id） 返回成功或失败
    // 姓名最少两位，最大50位 只能出现中文
    // 身份证号必须18位 且身份证出生日期不能大于当日：如不能出现2024年出生
    // id必填并且是数字
    /**--------------- @TODO 后期用AOP来完成@CheckIdCardDate的参数值校验 -----------------------**/
    @Operation(summary = "用户实名认证",description = "用户实名认证")
    @CheckIdCardDate
    @PostMapping("/realNameAuthentication")
    public Result realNameAuthentication(@RequestBody @Valid NameAuthenticationVO nameAuthenticationVO, HttpServletRequest request){
        String token = request.getHeader("Authorization");
        System.out.println("token = " + token);
        boolean b = StrUtil.hasBlank(token);
        if(b){
            return Result.error().msg("请先登录");
        }else{
            //校验是否过期
            boolean verify = JWTUtil.verify(token, secretKey.getBytes());
            if(verify){
                //解密
                final JWT jwt = JWTUtil.parseToken(token);
                String uid = jwt.getPayload("uid").toString();
                int uidInt = Integer.parseInt(uid);
                System.out.println("uidInt = " + uidInt);
                return Result.ok().msg(uid+"实名认证成功");
            }else{
                return Result.error().msg("登录过期");
            }
        }
    }

    /**
     * 周末作业
     * 1、注册30个用户
     * 2、分页查询这些用户，每页5个
     * 3、删除1个用户（逻辑删除） 让总数变成29个
     */
    @Operation(summary = "用户分页查询",description = "用户分页查询")
    @Parameters({
            @Parameter(name = "pageNumber",description = "第几页开始",required = true,example = "1"),
            @Parameter(name = "pageSize",description = "每页多少条",required = true,example = "10")
    })
    @GetMapping("/selectUserByPage")
    public Result<List<UserInfoDTO>> selectUserByPage(Integer pageNumber,Integer pageSize) {
        //分页
        Page<Users> usersPage = iUsersService.getBaseMapper().selectPage(PageDTO.of(pageNumber, pageSize), null);
        //lambda表达式
        //获取流
        List<UserInfoDTO> listDTO = usersPage.getRecords().stream()
                .map(user -> {
                    UserInfoDTO userInfoDTO = new UserInfoDTO();
                    //应该还有一个托敏等操作
                    BeanUtil.copyProperties(user, userInfoDTO);
                    return userInfoDTO;
                })
                .collect(Collectors.toList());
        return Result.ok(listDTO).count(usersPage.getTotal());
    }

    @Operation(summary = "删除一个用户",description = "通过id删除")
    @Parameters({
            @Parameter(name = "userId",description = "用户id",required = true,example = "1"),
    })
    //只能传数字和字符，不能传复杂数据
    @DeleteMapping("/delUserById/{userId}")
    public Result selectUserByPage(@PathVariable String userId) {
        boolean b = iUsersService.removeById(userId);
        return b ? Result.ok().msg("删除成功") : Result.error().msg("删除失败");
    }



}
